package main

import (
	"bytes"
	"context"
	"fmt"
	"gitee.com/shiqiyue/gqlgen-md/client"
	"gitee.com/shiqiyue/gqlgenc/introspection"
	"github.com/vektah/gqlparser/v2/ast"
	"github.com/vektah/gqlparser/v2/validator"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func main() {
	url := "http://120.37.177.122:61438/fin/finance/gql"
	//url = "http://120.37.177.122:61438/org/oranization/gql"
	//url = "http://120.37.177.122:61438/sys/system/gql"
	url = "http://120.37.177.122:61438/bi/mgr/gql"
	url = "http://120.37.177.122:61438/log_adm/adm/gql"
	ctx := context.Background()
	schema, err := loadSchema(ctx, url)
	if err != nil {
		log.Fatal(err)
	}
	mdBs := bytes.Buffer{}
	mdBs.WriteString(ApiInfo(ctx, url))

	if schema.Query != nil {
		if schema.Query.Fields != nil && len(schema.Query.Fields) > 0 {
			for _, field := range schema.Query.Fields {
				mdString := ApiToMDString(ctx, field, schema.Query, schema)
				mdBs.WriteString(mdString)
			}
		}
	}
	if schema.Mutation != nil {
		if schema.Mutation.Fields != nil && len(schema.Mutation.Fields) > 0 {
			for _, field := range schema.Mutation.Fields {
				mdString := ApiToMDString(ctx, field, schema.Mutation, schema)
				mdBs.WriteString(mdString)
			}
		}
	}
	//fmt.Println(mdBs.String())

	ioutil.WriteFile("test.md", mdBs.Bytes(), 0777)

}

func ApiInfo(ctx context.Context, url string) string {
	bs := bytes.Buffer{}
	bs.WriteString(fmt.Sprintf("# 接口说明 \n"))
	bs.WriteString("- 请求URL \n")
	bs.WriteString(fmt.Sprintf("`%s` \n", url))
	bs.WriteString("- 请求方式 \n")
	bs.WriteString("`HTTP请求(GQL方式)` \n")
	// 头部
	bs.WriteString("- 请求头参数 \n")
	bs.WriteString("| 参数名 | 类型 | 说明 | \n")
	bs.WriteString("| ------------- | ------ | ------------------------------- | \n")
	bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", "Authorization", "String", "用户登录成功返回的令牌"))
	return bs.String()
}

func TypeToMDString(ctx context.Context, level int, definition *ast.Definition, ty *ast.Definition, schema *ast.Schema) string {
	bs := bytes.Buffer{}
	tabStr := ""
	for i := 0; i < level; i++ {
		tabStr = tabStr + "&nbsp;&nbsp;&nbsp;&nbsp;"
	}
	//bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", attributeName, ty.Name, attributeDesc))
	if ty.Kind == ast.Object || ty.Kind == ast.InputObject {
		for _, field := range ty.Fields {
			typeName := field.Type.NamedType
			namedType := field.Type.NamedType
			if field.Type.Elem != nil {
				typeName = field.Type.Elem.NamedType + "[]"
				namedType = field.Type.Elem.NamedType
			}
			bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", tabStr+field.Name, typeName, ClearDesc(field.Description)))
			ty := schema.Types[namedType]
			if ty != nil {
				if ty.Kind == ast.Object || ty.Kind == ast.InputObject {
					bs.WriteString(TypeToMDString(ctx, level+1, definition, ty, schema))
				}
			}

		}
	}

	return bs.String()
}

func ClearDesc(description string) string {
	return strings.ReplaceAll(description, "\n", "")
}

func ApiToMDString(ctx context.Context, field *ast.FieldDefinition, definition *ast.Definition, schema *ast.Schema) string {
	if field.Name == "__schema" || field.Name == "__type" {
		return ""
	}

	bs := bytes.Buffer{}
	bs.WriteString(fmt.Sprintf("# %s \n", field.Description))
	bs.WriteString("- 请求URL \n")
	bs.WriteString(fmt.Sprintf("`%s %s` \n", definition.Name, field.Name))
	bs.WriteString("- 请求方式 \n")
	bs.WriteString("`HTTP请求(GQL方式)` \n")
	// 头部
	bs.WriteString("- 请求头参数 \n")
	bs.WriteString("| 参数名 | 类型 | 说明 | \n")
	bs.WriteString("| ------------- | ------ | ------------------------------- | \n")
	bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", "Authorization", "String", "用户登录成功返回的令牌"))
	// 入参
	bs.WriteString("- 参数 \n")
	bs.WriteString("| 参数名 | 类型 | 说明 | \n")
	bs.WriteString("| ------------- | ------ | ------------------------------- | \n")

	if field.Arguments != nil && len(field.Arguments) > 0 {
		for _, argument := range field.Arguments {
			typeName := argument.Type.NamedType
			namedType := argument.Type.NamedType
			if argument.Type.Elem != nil {
				typeName = argument.Type.Elem.NamedType + "[]"
				namedType = argument.Type.Elem.NamedType
			}
			bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", argument.Name, typeName, "-"))
			ty := schema.Types[namedType]
			if ty != nil {
				if ty.Kind == ast.InputObject {
					bs.WriteString(TypeToMDString(ctx, 1, definition, ty, schema))
				}
			}
		}
	}
	// 返回参数
	bs.WriteString("- 返回参数 \n")
	bs.WriteString("| 参数名 | 类型 | 说明 | \n")
	bs.WriteString("| ------------- | ------ | ------------------------------- | \n")
	if field.Type != nil {

		typeName := field.Type.NamedType
		namedType := field.Type.NamedType
		if field.Type.Elem != nil {
			typeName = field.Type.Elem.NamedType + "[]"
			namedType = field.Type.Elem.NamedType
		}
		bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", "-", typeName, "-"))
		ty := schema.Types[namedType]
		if ty != nil {
			if ty.Kind == ast.Object || ty.Kind == ast.InputObject {
				bs.WriteString(TypeToMDString(ctx, 1, definition, ty, schema))
			}
		}
	}

	// 返回示例
	//bs.WriteString("- 返回示例\n")
	//bs.WriteString("```json\n```")

	bs.WriteString("\n")
	return bs.String()
}

func loadSchema(ctx context.Context, url string) (*ast.Schema, error) {
	gqlclient := client.NewClient(http.DefaultClient, url)
	var res introspection.Query
	if err := gqlclient.Post(ctx, "Query", introspection.Introspection, &res, nil); err != nil {
		return nil, fmt.Errorf("introspection query failed: %w", err)
	}

	schema, err := validator.ValidateSchemaDocument(introspection.ParseIntrospectionQuery(url, res))
	if err != nil {
		return nil, fmt.Errorf("validation error: %w", err)
	}
	return schema, nil
}
